import config
import bubbles
import time
import os
import sys
import io
import subprocess
import eventlet
import asyncio
from copy import deepcopy
from pkgutil import walk_packages
from utils import *


class Miraigum:
	def __init__(self, startMirai=True):
		if startMirai:
			with open(config.miraicon.out, 'a', encoding='utf-8') as out:
				self.miraicon = subprocess.Popen(config.miraicon.executable, cwd=config.miraicon.cwd, stdin=subprocess.PIPE, stdout=out)
				time.sleep(config.miraicon.waitSeconds)

		self.blowBubbles()
		self.phone()
		self.currentBubble = None
		self.currentMessage = None

	def __del__(self):
		self.miraicon.stdin.write(b'stop\n')
		self.miraicon.stdin.flush()
		self.miraicon.wait(10)


	def nap(self):
		sys.exit(1)

	def sleep(self):
		sys.exit(0)

	def phone(self):
		with trying(False, False, False, False, False):
			post('verify', verifyKey=config.utils.verifyKey)

	def blowBubble(self, finder, name, ispkg):
		loader = finder.find_module(name)
		mod = loader.load_module(name)
		if hasattr(mod, 'register') and callable(mod.register):
			with trying():
				self.bubbles.append(mod.register())

	def blowBubbles(self):
		self.bubbles = []
		for finder, name, ispkg in walk_packages(config.miraigum.bubbles.paths):
			log('泡泡', name)
			self.blowBubble(finder, name, ispkg)

	def eatBiscuit(self):
		if os.path.exists(config.miraigum.biscuit.path):
			with trying():
				compiled = None
				with open(config.miraigum.biscuit.path, 'rb') as f:
					compiled = compile(f.read(), config.miraigum.biscuit.path, 'exec')
				os.rename(config.miraigum.biscuit.path,
						  time.strftime('%Y%m%d_%H%M%S').join(
							  os.path.splitext(config.miraigum.biscuit.path)))
				exec(compiled)
				s = config.miraigum.biscuit.succeedMsg
				log(s)
				mail(s)

	def wakeUp(self):
		log('糖糖喵喵叫~')
		while True:
			time.sleep(config.miraigum.sleepingSeconds)
			self.eatBiscuit()
			with trying():
				self.chat()

	def mirai(self):
		# log('糖糖在倾听……')
		res = None
		with trying(False, False, False, False, False):
			res = get(par('fetchMessage', count=10))
		while not res or res['code'] == 4:
			time.sleep(config.miraicon.waitSeconds)
			log('mirai连接中……', res)
			self.phone()
			with trying(False, False, False, False, False):
				res = get(par('fetchMessage', count=10))
		return res['data']

	def meow(self):
		# TODO support messages from bot's email.
		return []

	def chat(self):
		eventlet.monkey_patch()
		msgs = []
		with trying(False, False, False, False, False):
			msgs.extend(self.mirai())
		with trying(False, False, False, False, False):
			msgs.extend(self.meow())
		# log('糖糖在吹泡泡')
		for bub in self.bubbles:
			self.currentBubble = bub
			with trying():
				if bub.type == 'active':
					with eventlet.Timeout(config.miraigum.bubblesTimeout):
						bub.run(self)
				elif bub.type == 'passive' or bub.type == 'multimode':
					for msg in msgs:
						with trying():
							if shouldShadow(bub, msg):
								continue
						cpy = deepcopy(msg)
						self.currentMessage = cpy
						with eventlet.Timeout(config.miraigum.bubblesTimeout):
							bub.run(self, cpy)
				if bub.type == 'multimode':
					with eventlet.Timeout(config.miraigum.bubblesTimeout):
						bub.run(self)

if __name__ == '__main__':
	sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
	gum = Miraigum()
	setAuto(gum)
	gum.wakeUp()